//package Game

import Cards._
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.HashMap
import scala.util.Random

// debugging stuff
import java.io._

class Player(name:String, playerNumber:Int) {
  var hand:ArrayBuffer[Card] = new ArrayBuffer[Card]
  var role:String = "Sweeden"
  def getName:String = this.name
  def getNameNumber:Int = this.playerNumber

  // right now it does the comparison via the card value,
  // but, if weights were incorportated this could easily be fixed
  def sortHand = {
    var cardIndex = 0
    while(cardIndex != this.hand.length - 1) {
      // change this line when weights are introduced
      // change from getValue to getWeight
      if(this.hand(cardIndex).getValue > this.hand(cardIndex + 1).getValue) {
	var temp:Card = this.hand(cardIndex)
	this.hand(cardIndex) = this.hand(cardIndex + 1)
	this.hand(cardIndex + 1) = temp
	cardIndex = 0
      } else {
	cardIndex += 1
      }
    }
  }
  def playCard(lastCard:ArrayBuffer[Card]):ArrayBuffer[Card] = { //, cardWeights:HashMap[Int,Int]) = {
    // if they cant play, return an empty ArrayBuffer, indicating no play
    var cardsToPlay:ArrayBuffer[Card] = new ArrayBuffer[Card]
    var cardIndex:Int = 0
    if(lastCard.length > 0) {
      var cardFound:Boolean = false
      while(!cardFound) {
	// change this line when weights are introduced
	// change from getValue to getWeight
	if(this.hand(cardIndex).getValue > lastCard(0).getValue) {
	  // expand this section when we search for pairs + trips + quads
	  cardsToPlay += this.hand(cardIndex)
	  this.hand -= this.hand(cardIndex)
	  cardFound = true
	} else {
	  if(cardIndex + 1 == this.hand.length) {
	    // if we added another to the index and ran again, we would
	    // get an out of bounds exception. so, say we have 'found' a card
	    // and return the empty play, indicating a pass
	    cardFound = true
	  } else {
	    cardIndex += 1
	  }
	}
      }
    } else {
      cardsToPlay += this.hand(cardIndex)
      this.hand -= this.hand(cardIndex)
    }
    return cardsToPlay
  }
  def recieveCards(cards:ArrayBuffer[Card]) = {
    for(card <- cards) {
      this.hand += card
    }
  }
  def giveCards(number:Int,fromWhere:String):ArrayBuffer[Card] = {
    var cardsToGive:ArrayBuffer[Card] = new ArrayBuffer[Card]
    if(fromWhere == "high") {
      if(number == 1) {
	cardsToGive += hand(hand.length - 1)
	hand -= hand(hand.length - 1)
      } else {
	cardsToGive ++= hand.slice(hand.length - 2, hand.length)
	hand --= hand.slice(hand.length - 2,hand.length)
      }
    } else {
      if(number == 1) {
	cardsToGive += hand(0)
	hand -= hand(0)
      } else {
	cardsToGive ++= hand.slice(0,1)
	hand --= hand.slice(0,1)
      }
    }
    println("cards to give")
    for(card <- cardsToGive) {
      println(card)
    }
    return cardsToGive
  }
  override def toString():String = {
    return this.getName
  }
}

object Game {
  var debug:Boolean = true
  def main(args: Array[String]) {
    if(this.debug) {println("Starting!")}

    // Get the number of players
    val numPlayers = getPlayers()
    // setup our player arrays, each indicating a different stage of play
    // the aggregate players
    var players:ArrayBuffer[Player] = new ArrayBuffer[Player]
    // the players currently able to play
    var activePlayers:ArrayBuffer[Player] = new ArrayBuffer[Player]
    // and the players who have emptied their hands
    var finishedPlayers:ArrayBuffer[Player] = new ArrayBuffer[Player]

    // Initilize the players in the players variable
    // then set up the active players
    for (i <- 0 to numPlayers - 1) {
      players += new Player("Steve",i)
      activePlayers += players(i)
    }

    // setup the deck, create and shuffle
    var deck:Deck = new Deck()
    println("Main: " + deck.deck.length)
    deck.deck = shuffleDeck(deck)
    // deal the cards out to the players
    println("Post-Shuffle: " + deck.deck.length)
    var playerIndex:Int = 0
    for(card <- deck.deck) {
      var cardsToGive:ArrayBuffer[Card] = new ArrayBuffer[Card]
      cardsToGive += card
      activePlayers(playerIndex).recieveCards(cardsToGive)
      if(playerIndex == 3) {
	playerIndex = 0
      } else {
	playerIndex += 1
      }
    }

    // have each player sort their hand
    for(player <- activePlayers) {
      player.sortHand
    }

    // for testing purposes, lets simulate that a hand was completed
    // and exchange cards
    /*
    println("Exchange cards")
    var giveToPres:ArrayBuffer[Card] = activePlayers(activePlayers.length - 1).giveCards(2,"high")
    var givetoVP:ArrayBuffer[Card] = activePlayers(activePlayers.length - 2).giveCards(1,"low")
    */
//    activePlayers(0).recieveCards(activePlayers(-1).giveCards(2,"high"))
//    activePlayers(1).recieveCards(activePlayers(-2).giveCards(1,"low"))

    // debugging
    var output = new java.io.FileOutputStream("hand")
    var outStream = new java.io.PrintStream(output)
    for(player <- players) {
      outStream.println("Player " + player.getNameNumber)
      for(card <- player.hand) {
	outStream.println(card)
      }
      outStream.println("-----")
    }
    outStream.println("Starting")
    playerIndex = 0
    var lastCard:ArrayBuffer[Card] = new ArrayBuffer[Card]
    var passCounter:Int = 0
    while(activePlayers.length > 1) {
      var madePlay:Boolean = false
      var pileReset:Boolean = false
      var playerRemoved:Boolean = false
      var twoPlayed:Boolean = false
      var player:Player = activePlayers(playerIndex)

      var cardPlayed:ArrayBuffer[Card] = player.playCard(lastCard)
      if(cardPlayed.length > 0) {
	madePlay = true
	passCounter = 0
	if(cardPlayed(0).getValue == 2) {
	  // reset the pile
	  println("Player " + player.getNameNumber + 
		  " played a 2, clearing pile")
	  outStream.println("Player " + player.getNameNumber +
			    " played a 2, clearing pile")
	  lastCard = new ArrayBuffer[Card]
	  pileReset = true
	  twoPlayed = true
	} else {
	  println("Player " + player.getNameNumber + " played " + cardPlayed(0))
	  outStream.println("Player " + player.getNameNumber + " played " +
			    cardPlayed(0))
	  lastCard = cardPlayed
	}
	if(player.hand.length == 0) {
	  println("player " + player.getNameNumber + " is out of cards <-----")
	  outStream.println("Player " + player.getNameNumber + 
			    " is out of cards <----")
	  outStream.println("PlayerIndex: " + playerIndex)
	  activePlayers -= player
	  finishedPlayers += player
	  playerRemoved = true
	}
      } else {
//	println("Player " + player.getNameNumber + " passed")
//	println("Current pass counter: pre-check  " + passCounter)
	outStream.println("Player " + player.getNameNumber + " passed")
	outStream.println("Current pass counter: pre-check " + passCounter)
	if(passCounter + 1 >= activePlayers.length) {
//	  println("All players passed, clearing pile")
	  outStream.println("All players passed, clearing pile")
	  lastCard = new ArrayBuffer[Card]
	  pileReset = true
	  passCounter = 0
	} else {
	  passCounter += 1
	}
//	println("Current pass counter: post-check " + passCounter)
	outStream.println("Current pass counter: post-check " + passCounter)
      }
      // trickiest part...
      // the only times we need to take special care is when either a pile reset
      // occured, and or a player was removed because we need to make sure we
      // dont get an IndexOutOfBounds exception.
      // whew...
      if(twoPlayed & playerRemoved) {
	if(playerIndex == activePlayers.length) {
	  playerIndex = 0
	  outStream.println("Player " + player.getNameNumber +
			    " with a two")
	}
      } else if(twoPlayed) {
	// do nothing because we dont want it to hit the else
      } else if(pileReset & playerRemoved) {
	outStream.print("The pile was reset and a player was removed")
	if(playerIndex == activePlayers.length) {
	  playerIndex = 0
	  outStream.print(" and the index was reset")
	} 
	outStream.println()
      } else if(playerRemoved) {
	outStream.print("A player was removed")
	if(playerIndex == activePlayers.length) {
	  playerIndex = 0
	  outStream.print(" and the index was reset")
	}
	outStream.println()
      } else {
	if(playerIndex == activePlayers.length - 1) {
	  outStream.println("The player index looped")
	  playerIndex = 0
	} else {
	  outStream.println("The player index was increased")
	  playerIndex += 1
	}
      }
    }
    // now that play is done, we need to add the last player into the
    // finished players list
    finishedPlayers += activePlayers(0)
    finishedPlayers = finishedPlayers.reverse
    // ok, now play is done. for debuggin purposes lets print some stuff
    for(player <- players) {
      println("Player " + player.getNameNumber)
      println("Hand: " + player.hand.length)
      outStream.println("Player " + player.getNameNumber)
      outStream.println("Hand: " + player.hand.length)
      if(player.hand.length == 0) {
	println("player went out")
	outStream.println("player went out")
      }
    }
    finishedPlayers.foreach(p => println(p.getNameNumber))
    // printout the crucial variable... maybe we will find something
    outStream.println("PlayerIndex: " + playerIndex)
  }
  def shuffleDeck(deck:Deck):ArrayBuffer[Card] = {
    // create a deck to put the shuffled cards in
    var shuffledDeck:ArrayBuffer[Card] = new ArrayBuffer[Card]
    var random:Random = Random
    // shuffle the cards
    for(deckIndex <- 0 to deck.deck.length - 1) {
      var index = random.nextInt(deck.deck.length)
      shuffledDeck += deck.deck(index)
      deck.deck -= deck.deck(index)
    }
    // return the shuffled deck
    return shuffledDeck
  }
  def getPlayers():Int = {
//    print("How many players? ")
//    val numPlayers:Int = readInt()
    val numPlayers:Int = 4
    return numPlayers
  }
}
